package com.study.cloud.gateway.client.core;

import com.study.cloud.gateway.client.support.dubbo.DubboConstants;
import com.study.cloud.gateway.common.constants.BasicConst;
import com.study.cloud.gateway.common.rule.ServiceDefinition;
import com.study.cloud.gateway.common.rule.invoker.DubboServiceInvoker;
import com.study.cloud.gateway.common.rule.invoker.HttpServiceInvoker;
import com.study.cloud.gateway.common.rule.invoker.ServiceInvoker;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.spring.ServiceBean;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * 注解扫描类
 *
 * @author wangwancheng
 * @create 2025/7/19 19:06
 */
public class ApiAnnotationScanner {

    /**
     * 单例
     **/
    private ApiAnnotationScanner() {
    }

    private class SingletonHolder {
        private static final ApiAnnotationScanner INSTANCE = new ApiAnnotationScanner();
    }

    public static ApiAnnotationScanner getInstance() {
        return SingletonHolder.INSTANCE;
    }

    public ServiceDefinition scanner(Object bean, Object... args){

        Class<?> clazz = bean.getClass();
        if (!clazz.isAnnotationPresent(ApiService.class)){
            return null;
        }
        ApiService apiService = clazz.getAnnotation(ApiService.class);
        String serviceId = apiService.serviceId();
        String version = apiService.version();
        ApiProtocol protocol = apiService.protocol();
        String patternPath = apiService.patternPath();

        Map<String/**invokerPath**/, ServiceInvoker> invokeMap = new HashMap<>();
        Method[] methods = clazz.getMethods();
        if (methods != null && methods.length > 0){
            for (Method method : methods){
                ApiInvoker apiInvoker = method.getAnnotation(ApiInvoker.class);
                if (apiInvoker == null){
                    continue;
                }
                String invokerPath = apiInvoker.path();
                switch ( protocol){
                    case HTTP :{
                        HttpServiceInvoker httpServiceInvoker =  createHttpServiceInvoker(invokerPath);
                        invokeMap.put(invokerPath,httpServiceInvoker);
                        break;
                    }
                    case DUBBO :{
                        ServiceBean<?> serviceBean = (ServiceBean<?>) args[0];
                        DubboServiceInvoker dubboServiceInvoker = createDubboServiceInvoker(invokerPath,serviceBean,method);
                        String dubboVersion = dubboServiceInvoker.getVersion();
                        //设置dubbo版本
                        if (StringUtils.isNoneBlank(dubboVersion)){
                            version = dubboVersion;
                        }
                        invokeMap.put(invokerPath,dubboServiceInvoker);
                        break;
                    }
                    default :{
                        throw new RuntimeException("不支持的协议");
                    }
                }
            }
        }
        //创建服务定义信息
        ServiceDefinition serviceDefinition = ServiceDefinition.builder()
                .uniqueId(serviceId + BasicConst.COLON_SEPARATOR + version)
                .serviceId(serviceId)
                .version(version)
                .protocol(protocol.getProtocol())
                .patternPath(patternPath)
                .enable(true)
                .build();
        return serviceDefinition;
    }

    /**
     * 构建dubboserviceInvoker对象
     * @param invokerPath
     * @param serviceBean
     * @param method
     * @return
     */
    private DubboServiceInvoker createDubboServiceInvoker(String invokerPath, ServiceBean<?> serviceBean, Method method) {


        String methodName = method.getName();
        String registerAddress = serviceBean.getRegistry() != null ? serviceBean.getRegistry().getAddress() : null;
        String interfaceClass = serviceBean.getInterface();

        DubboServiceInvoker dubboServiceInvoker = new DubboServiceInvoker();
        dubboServiceInvoker.setInvokerPath(invokerPath);

        dubboServiceInvoker.setRegisterAddress(registerAddress);
        dubboServiceInvoker.setInterfaceClass(interfaceClass);
        dubboServiceInvoker.setMethodName(methodName);

        String[] parameterTypes = new String[method.getParameterCount()];
        Class<?>[] parameterTypesClass = method.getParameterTypes();
        for (int i = 0; i < parameterTypesClass.length; i++) {
            parameterTypes[i] = parameterTypesClass[i].getName();
        }
        dubboServiceInvoker.setParameterTypes(parameterTypes);
        Integer timeout = serviceBean.getTimeout();
        //如果没有超时时间， 赋予默认的超时时间
        if (timeout == null || timeout <= 0){
            timeout = DubboConstants.DUBBO_TIMEOUT;
        }
        dubboServiceInvoker.setTimeout(timeout);
        dubboServiceInvoker.setVersion(serviceBean.getVersion());
        return dubboServiceInvoker;
    }

    /**
     * 构建httpServiceInvoker对象
     * @param invokerPath
     * @return
     */
    private HttpServiceInvoker createHttpServiceInvoker(String invokerPath) {

        HttpServiceInvoker httpServiceInvoker = new HttpServiceInvoker();
        httpServiceInvoker.setInvokerPath(invokerPath);
        return httpServiceInvoker;
    }


}
